package com.example.springboot.demo;

import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import org.springframework.remoting.RemoteAccessException;

import java.util.concurrent.TimeUnit;

/**
 * guava-retry重试
 * <p> guava-retry在使用上更便捷，更灵活，能根据方法返回值来判断是否重试，
 * <p> 而Spring-retry只能根据抛出的异常来进行重试
 *
 */
public class GuavaRetryTest1 {

    public static void main(String[] args) {
        Retryer<Boolean> retry = RetryerBuilder.<Boolean>newBuilder()
                .retryIfExceptionOfType(RemoteAccessException.class)//设置异常重试源
                .retryIfResult(Boolean.FALSE::equals)  //设置根据结果重试
                .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS)) //设置等待间隔时间
                .withStopStrategy(StopStrategies.stopAfterAttempt(3)) //设置最大重试次数
                .withRetryListener(new RetryListener() {
                    // 当发生重试之后，假如我们需要做一些额外的处理动作，比如log一下异常,可以注册多个RetryListener，会按照注册顺序依次调用
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        System.out.println("第【"+attempt.getAttemptNumber()+"】次调用");
                    }
                })
                .build();
        try {
            retry.call(() -> RetryTest.retryTask("abc"));
        } catch (Exception e) {
            e.printStackTrace();
        }


        //run
        //1. 遇到了我们指定的需要重试的异常，进行重试，间隔是3秒
        //2. 重试次数超过了最大重试次数， Retrying failed to complete successfully after 3 attempts.
        //3. 返回为true，直接结束重试
        //4. 遇到了没有指定重试的异常，结束重试
        //5. 返回false，重试

        /**
         * 拥有更灵活的配置重试策略
         * retryIfException：抛出 runtime 异常、checked 异常时都会重试，但是抛出 error 不会重试。
         *
         * retryIfRuntimeException：只会在抛 runtime 异常的时候才重试，checked 异常和error 都不重试。
         *
         * retryIfExceptionOfType：允许我们只在发生特定异常的时候才重试，比如NullPointerException 和 IllegalStateException 都属于 runtime 异常，也包括自定义的error。
         *
         */

        /**
         * retryIfResult: 可以指定你的 Callable 方法在返回值的时候进行重试
         *
         * 返回false重试： .retryIfResult(Predicates.equalTo(false))
         *
         * 以_error结尾才重试： .retryIfResult(Predicates.containsPattern("_error$"))
         *
         * 返回为空时重试： .retryIfResult(res-> res==null)
         *
         */

    }
}
